package org.columba.mail.gui.socialnet;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.Stroke;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JLabel;

import org.apache.commons.collections.Predicate;

import edu.uci.ics.jung.graph.ArchetypeEdge;
import edu.uci.ics.jung.graph.ArchetypeVertex;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedEdge;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.decorators.AbstractEdgePaintFunction;
import edu.uci.ics.jung.graph.decorators.EdgeStringer;
import edu.uci.ics.jung.graph.decorators.EdgeStrokeFunction;
import edu.uci.ics.jung.graph.decorators.NumberEdgeValue;
import edu.uci.ics.jung.graph.decorators.UserDatumNumberEdgeValue;
import edu.uci.ics.jung.graph.decorators.VertexPaintFunction;
import edu.uci.ics.jung.graph.decorators.VertexShapeFunction;
import edu.uci.ics.jung.graph.decorators.VertexStringer;
import edu.uci.ics.jung.utils.MutableDouble;
import edu.uci.ics.jung.visualization.GraphLabelRenderer;
import edu.uci.ics.jung.visualization.PickedInfo;
import edu.uci.ics.jung.visualization.PluggableRenderer;

public class SocialNetWorkRender extends PluggableRenderer
{
	    //public Graph network;
	    private double min;
	    private double max;
	    protected NumberEdgeValue edge_weight = new UserDatumNumberEdgeValue("edge_weight");
	    private String labelAlgoType = "jung.algorithms.importance.DegreeDistributionRanker.RankScore";
	    private Set mPred;
		//private Vertex mFrom;
		//private Vertex mTo;
	    
	    public SocialNetWorkRender()
	    {
	    	mPred = new HashSet();
	        min = (-1.0D / 0.0D);
	        max = (1.0D / 0.0D);
	        setVertexStringer(new MyVertexStringer());
	        setVertexShapeFunction(new MyVertexShapeFunction());
	        setVertexIncludePredicate(new MyVertexIncludePredicate());
	        setVertexPaintFunction(new MyVertexPaintFunction(this, Color.BLACK, Color.RED, Color.ORANGE));
	        
	        setEdgeShapeFunction(new edu.uci.ics.jung.graph.decorators.EdgeShape.Line());
	        setEdgeStrokeFunction(new MyEdgeStrokeFunction(edge_weight));
	        setEdgeIncludePredicate(new MyEdgeIncludePredicate());
	        setEdgePaintFunction(new MyEdgePaintFunction());   
	        setEdgeStringer(new MyEdgeStringer());
	        
	        setGraphLabelRenderer(new MyGraphLabelRenderer());
	    }
	    
	    boolean isBlessed( Edge e ) {
			Vertex v1= (Vertex) e.getEndpoints().getFirst()	;
			Vertex v2= (Vertex) e.getEndpoints().getSecond() ;
			return mPred.contains(v1) && mPred.contains( v2 );
	    }
	    
	public class MyVertexShapeFunction implements VertexShapeFunction
	{
		public Shape getShape(Vertex v)
        {
			double minSize = 8D;
	        double maxSize = 30D;
	        double factor = 1.0D;
	        int r = (new Double(minSize)).intValue();
	        Object o = v.getUserDatum(labelAlgoType);
	        if(o != null)
	        {
	            double val = ((MutableDouble)o).doubleValue();
	            r = (new Double(minSize + (((val - min) * (maxSize - minSize)) / (max - min)) * factor)).intValue();
	        }
	        return new java.awt.geom.Ellipse2D.Double(-r, -r, 2 * r, 2 * r);
        }
	}
	    
    public class MyEdgePaintFunction extends AbstractEdgePaintFunction 
	{
		public Paint getDrawPaint(Edge e) 
		{
			if ( mPred == null || mPred.size() == 0) return Color.BLACK;
			if( isBlessed( e )) {
				//return new Color(0.0f, 205.0f, 0.0f, 0.5f);//Color.BLUE;
				return Color.BLUE;
			} else {
				return Color.LIGHT_GRAY;
			}
		}
	}
    
    public class MyVertexStringer implements VertexStringer
    {
    	 public String getLabel(ArchetypeVertex v)
         {
 	        String label = "";
	        if(v instanceof SocialNetWorkActorVertex)
	        {
	        	SocialNetWorkActorVertex av = (SocialNetWorkActorVertex)v;
	        	//label = (new StringBuilder(String.valueOf(av.name))).append(" ").append(shiftDecimal(((MutableDouble)av.getUserDatum(labelAlgoType)).doubleValue(), 3)).toString();
	        	label = av.name;
	        }
	        return label;
         }
    }
    
    public class MyEdgeStrokeFunction implements EdgeStrokeFunction
    {
        protected final Stroke basic = new BasicStroke(1);
        protected final Stroke heavy = new BasicStroke(2);
        protected final Stroke dotted = PluggableRenderer.DOTTED;
        
        protected boolean weighted = false;
        protected NumberEdgeValue edge_weight;
        
        public MyEdgeStrokeFunction(NumberEdgeValue edge_weight)
        {
            this.edge_weight = edge_weight;
        }
        
        public void setWeighted(boolean weighted)
        {
            this.weighted = weighted;
        }
        public Stroke getStroke(Edge e)
        {
            if (weighted)
            {
                if (drawHeavy(e))
                    return heavy;
                else
                    return dotted;
            }
            else
                return basic;
        }
        
        protected boolean drawHeavy(Edge e)
        {
            double value = edge_weight.getNumber(e).doubleValue();
            if (value > 0.7)
                return true;
            else
                return false;
        }
    }
    
    public class MyEdgeStringer implements EdgeStringer
    {
        public String getLabel(ArchetypeEdge e)
        {
            return "";
        }
    }
    
    public class MyGraphLabelRenderer implements GraphLabelRenderer
    {
    	 public Component getGraphLabelRendererComponent(JComponent vv, Object value, Font font, boolean isSelected, Vertex vertex)
         {
             JLabel label = new JLabel(value.toString(), 0);
             label.setOpaque(true);
             label.setBackground(new Color(0, 0, 255, 66));
             label.setForeground(Color.black);
             return label;
         }

         public Component getGraphLabelRendererComponent(JComponent vv, Object value, Font font, boolean isSelected, Edge edge)
         {
             if(value.toString() != "")
             {
                 JLabel label = new JLabel(value.toString(), 0);
                 label.setOpaque(true);
                 label.setBackground(new Color(0, 0, 0, 75));
                 if((new Double(value.toString())).doubleValue() > 0.0D)
                     label.setForeground(Color.green);
                 if((new Double(value.toString())).doubleValue() == 0.0D)
                     label.setForeground(Color.white);
                 if((new Double(value.toString())).doubleValue() < 0.0D)
                     label.setForeground(Color.red);
                 return label;
             } else
             {
                 return new JLabel();
             }
         }

         public boolean isRotateEdgeLabels()
         {
             return false;
         }

         public void setRotateEdgeLabels(boolean flag)
         {
         }
    }
    
    public class MyEdgeIncludePredicate implements Predicate
    {
        public boolean evaluate(Object o)
        {
        	return true;
        }
    }
    
    public class MyVertexIncludePredicate implements Predicate
    {
        public boolean evaluate(Object o)
        {
        	return true;
        }
    }
    
	public class MyVertexPaintFunction implements VertexPaintFunction {
		
	    protected Paint draw_paint;
	    protected Paint fill_paint;
	    protected Paint picked_paint;
	    protected PickedInfo pi;
	    
	    /**
	     * 
	     * @param pi            specifies which vertices report as "picked"
	     * @param draw_paint    <code>Paint</code> used to draw vertex shapes
	     * @param fill_paint    <code>Paint</code> used to fill vertex shapes
	     * @param picked_paint  <code>Paint</code> used to fill picked vertex shapes
	     */
		public MyVertexPaintFunction(PickedInfo pi, Paint draw_paint, Paint fill_paint, Paint picked_paint)
		{
	        if (pi == null)
	            throw new IllegalArgumentException("PickedInfo instance must be non-null");
	        this.pi = pi;
	        this.draw_paint = draw_paint;
	        this.fill_paint = fill_paint;
	        this.picked_paint = picked_paint;
		}

		public Paint getDrawPaint(Vertex v) {
			return Color.RED;
		}
		
		public Paint getFillPaint( Vertex v ) {
			//if ( v == mFrom) 
				//return Color.BLUE;
			//if ( v == mTo ) 
				//return Color.BLUE;
			if ( mPred.size()==0 ) 
			{
				if (pi.isPicked(v))
				{
					return picked_paint;
				}       
				return Color.red;
			} 
			else 
			{
				if ( mPred.contains(v)) 
				{
					return Color.GREEN;
			    } else 
			    {
					return Color.RED;
				}
			}
		}
	}
    
    public void addToSignSet(Vertex [] vertexs)
    {
    	mPred.clear();
    	if(vertexs==null)
    		return;
    	for(int i=0; i<vertexs.length; i++)
    	{
    		mPred.add(vertexs[i]);
    	}
    }

}
